#include "precompiled.h"
#include "itemdatabase.h"
using namespace weo::engine::item;
using namespace boost::multi_index;
using namespace std;
BOOST_CLASS_TRACKING(Itemdatabase, boost::serialization::track_never);
Itemdatabase *Itemdatabase::s_Itemdatabase = NULL;
Itemdatabase::Itemdatabase()
{
}
const std::vector<Item> Itemdatabase::getbyName(string name) const
{
    std::vector<Item> retval;
    std::pair<Itemdbcontainer::nth_index<1>::type::iterator,Itemdbcontainer::nth_index<1>::type::iterator> itpair = m_ItemDB.get<1>().equal_range(name);
    Itemdbcontainer::nth_index<1>::type::iterator it = itpair.first;
    retval.assign(itpair.first,itpair.second);
    return retval;
}
const std::vector<const Item*> Itemdatabase::getPtrbyName(string name) const
{
    std::vector<const Item*> retval;
    std::pair<Itemdbcontainer::nth_index<1>::type::iterator,Itemdbcontainer::nth_index<1>::type::iterator> itpair = m_ItemDB.get<1>().equal_range(name);
    Itemdbcontainer::nth_index<1>::type::iterator it;
    for(it=itpair.first;it!=itpair.second;it++)
    {
        const Item * item = &*it;
        retval.push_back(item);
    }
    return retval;
}
const Item* Itemdatabase::getPtrbyId(unsigned int id) const
{
    Itemdbcontainer::nth_index<0>::type::iterator it = m_ItemDB.get<0>().find(id);
    if(it == m_ItemDB.get<0>().end()) return Item::None();
    else return &*it;
}
const Item Itemdatabase::getbyId(unsigned int id) const
{
    Itemdbcontainer::nth_index<0>::type::iterator it = m_ItemDB.get<0>().find(id);
    if(it == m_ItemDB.get<0>().end()) return *Item::None();
    else return *it;
}
void Itemdatabase::setItem(const Item &item)
{
    Itemdbcontainer::nth_index<0>::type::iterator it = m_ItemDB.get<0>().find(item.Id());
    if(it == m_ItemDB.get<0>().end())
    {
        m_ItemDB.insert(item);
    }
    else m_ItemDB.replace(it,item);	

}
const std::vector<const Item*> Itemdatabase::getPtrbyType(int type, int slot, int subtype)  const
{
    std::vector<const Item*> retval;
    std::pair<Itemdbcontainer::nth_index<2>::type::iterator,Itemdbcontainer::nth_index<2>::type::iterator> itpair;
    if(slot == 0)
    {
        itpair= m_ItemDB.get<2>().equal_range(boost::make_tuple(type));
    }
    else if(subtype == 0)
    {
        itpair= m_ItemDB.get<2>().equal_range(boost::make_tuple(type,slot));
    }
    else itpair = m_ItemDB.get<2>().equal_range(boost::make_tuple(type,slot,subtype));
    Itemdbcontainer::nth_index<2>::type::iterator it;
    for(it=itpair.first;it!=itpair.second;it++)
    {
        const Item * item = &*it;
        retval.push_back(item);
    }
    return retval;
}
const std::vector<Item> Itemdatabase::getbyType(int type, int slot, int subtype) const 
{
    std::vector<Item> retval;
    std::pair<Itemdbcontainer::nth_index<2>::type::iterator,Itemdbcontainer::nth_index<2>::type::iterator> itpair;
    if(slot == 0)
    {
        itpair = m_ItemDB.get<2>().equal_range(boost::make_tuple(type));
    }
    else if(subtype == 0)
    {
        itpair = m_ItemDB.get<2>().equal_range(boost::make_tuple(type,slot));
    }
    else itpair= m_ItemDB.get<2>().equal_range(boost::make_tuple(type,slot,subtype));
    Itemdbcontainer::nth_index<2>::type::iterator it = itpair.first;
    retval.assign(itpair.first,itpair.second);
    return retval;
}
Itemdatabase* Itemdatabase::getInstance()
{
    if(!s_Itemdatabase)
    {
        s_Itemdatabase = new Itemdatabase();
    }
    return s_Itemdatabase;
}
void Itemdatabase::fixAllowed()
{
    Itemdbcontainer::nth_index<0>::type::iterator it;
    std::pair<Itemdbcontainer::nth_index<1>::type::iterator,Itemdbcontainer::nth_index<1>::type::iterator> itpair;
    for(it = m_ItemDB.get<0>().begin(); it!= m_ItemDB.get<0>().end();it++)
    {
        if(it->Set()->Name().empty()) continue;
        for(unsigned int i = 0;i<it->Set()->Item()->size();i++)
        {
            itpair = m_ItemDB.get<1>().equal_range(it->Set()->Item()->at(i));
            Itemdbcontainer::nth_index<1>::type::iterator fit;
            for(fit = itpair.first;fit!=itpair.second;fit++)
            {
                if(fit->Set()->Name().empty()) continue;
                if(fit->Allowed() < it->Allowed())
                {
                    Item item = *it;
                    Item fitem = *fit;
                    item.setAllowed(fitem.Allowed());
                    setItem(item);
                }
                if(fit->Allowed() > it->Allowed())
                {
                    Item item = *it;
                    Item fitem = *fit;
                    fitem.setAllowed(item.Allowed());
                    setItem(fitem);
                }
            }
        }
    }
}
void Itemdatabase::createStaticData()
{
    Itemdbcontainer::nth_index<0>::type::const_iterator it;
    google::sparse_hash_set<std::string> m_AreaMap;
    std::vector<std::string>::const_iterator it2;
    m_MaxLevel = 0;
    m_MinLevel = 99999;
    for (it = m_ItemDB.get<0>().begin();it!= m_ItemDB.get<0>().end();it++)
    {
        const Item *item = &*it;
        for(it2 = item->Areaname()->begin();it2 != item->Areaname()->end();it2++)
        {
            if(m_AreaMap.count(*it2) == 0)
            {
                m_AreaMap.insert(*it2);
                m_AreaVector.push_back(*it2);
            }
        }
        if(item->Level() > m_MaxLevel) m_MaxLevel = item->Level();
        if(item->Level() < m_MinLevel) m_MinLevel = item->Level();
    }
}
std::map<unsigned int, bool> Itemdatabase::getAllItemsMap() const
{
    std::map<unsigned int, bool> retval;
    Itemdbcontainer::nth_index<0>::type::const_iterator it;
    for (it = m_ItemDB.get<0>().begin();it!= m_ItemDB.get<0>().end();it++)
    {
        const Item * item = &*it;
        retval[item->Id()] = false;
    }
    return retval;
}
void Itemdatabase::SaveNew() const
{
    Itemdbcontainer::nth_index<0>::type::const_iterator it;
    ticpp::Document doc;  
    ticpp::Declaration* decl;
    ticpp::Element* root;
    ticpp::Element* ele;
    try
    {
        decl = new (UseGC) ticpp::Declaration( "1.0", "", "" );  
        doc.LinkEndChild( decl );  
        root = new ticpp::Element( "itemdatabase" );  
        doc.LinkEndChild( root );  
        for (it = m_ItemDB.get<0>().begin();it!= m_ItemDB.get<0>().end();it++)
        {
            const Item * item = &*it;
            ele = new (UseGC) ticpp::Element("item");
            item->toXmlElement(ele);
            root->LinkEndChild( ele ); 
        }
        string file_name = "itemdbnew.xbz";
        boost::iostreams::filtering_ostream out;
        out.push(boost::iostreams::bzip2_compressor());
        out.push(boost::iostreams::file_descriptor_sink(file_name.c_str()));
        out << doc;
    }
    catch( ticpp::Exception& ex )
    {
    }
}
bool Itemdatabase::LoadNew()
{
    string file_name = "itemdbnew.xbz";
    boost::iostreams::filtering_istream in;
    ticpp::Document *doc = new (UseGC) ticpp::Document();;  
    try
    {
        in.push(boost::iostreams::bzip2_decompressor());
        in.push(boost::iostreams::file_descriptor_source(file_name.c_str()));
    }
    catch(boost::iostreams::filtering_istream::failure e)
    {
        std::cout << "Error while loading file" << std::endl;
        return false;
    }
    try
    {
        in >> *doc;
        ticpp::Element * root = doc->FirstChildElement("itemdatabase",true);
        if(root != NULL)
        {
            ticpp::Element *pItem = root->FirstChildElement("item",false);
            while(pItem != NULL)
            {
                Item temp;
                temp.fromXmlElement(pItem);
                Itemdatabase::setItem(temp);
                pItem = pItem->NextSiblingElement(false);
            }
        }
            delete doc;
    }
    catch( ticpp::Exception& ex )
    {
    }
}